/*
 * ULSF Sagittarius IDA
 * Copyright (C) 2012, John Pritchard, all rights reserved.
 * 
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */
package sagittarius.design;

import sagittarius.airfoil.Airfoil;

/**
 * This class defines a hyperbolic section with span distribution of
 * volume functions parameterized via the {@link Visualization} greek
 * parameters.
 * 
 * <h3>Span distribution function</h3>
 * 
 * <pre>
 * y *= \alpha + n^{\beta} + t^{\gamma} + \delta*((\epsilon*u)^{\zeta})
 * </pre>
 * 
 * <p> Neutral effect with field values
 * 
 * <pre>
 * y *= 1; -2 + 1 + 1 + 1; \alpha = -2, \beta = 0, \gamma = 0, \delta = 1, \epsilon = 1, \zeta = 0
 * </pre></p>
 * 
 * <h3>Radius distribution function</h3>
 * 
 * <pre>
 * z *= ((\eta-y^{\theta})-(\iota+y^{\kappa}))
 * </pre>
 * 
 * <p> Neutral effect with field values
 * 
 * <pre>
 * z *= 1 ; (3 - 1) - (0 + 1); \eta = 3, \theta = 0, \iota = 0, \kappa = 0
 * </pre></p>
 */
public final class ModelHyperbolicSpan
    extends AbstractModel
    implements Model.Path
{
    /**
     * Area of the shell section
     */
    public final float area;

    /**
     * {@link Visualization} ordered (Y,Z)+ vertices of the shell in CCW order
     * from top (Y+) to bottom with a shared midpoint and identical
     * endpoints.
     */
    public final float[] vertices;

    private final ModelHyperbolicShell model;


    public ModelHyperbolicSpan(VolumeHyperbolic volume, double station, double x,
                               double uniform, float area)
    {
        super();

        this.model = new ModelHyperbolicShell(volume,station);

        final float[] vertices = this.model.generatePath(area);
        /*
         * Span distribution function
         */
        final double b = Math.pow(volume.getSpanRatio(),volume.beta);
        final double g = Math.pow(this.getHyperbolicSectorRatio(),volume.gamma);
        final double d = (volume.delta*Math.pow(volume.epsilon*uniform,volume.zeta));
        final double s = (volume.alpha + b + g + d);

        final int count = vertices.length, count2 = (count>>1);

        double span = 0.0;

        for (int cc = 0; cc < count; cc+=2){

            double y = vertices[cc+X];
            /*
             * Span distribution
             */
            y = (y * s); //clamp?

            vertices[cc+X] = (float)y;

            span = Math.max(span,y);
        }
        final double iuniform = (1.0/uniform);

        for (int cc = 0; cc < count; cc+=2){

            double y = vertices[cc+X];
            double z = vertices[cc+Y];

            /*
             * Radius distribution function
             */
            final double t = Math.pow(y,volume.theta);
            final double k = Math.pow(y,volume.kappa);
            final double r = ((volume.eta-t)-(volume.iota+k));

            final double zr = (z * r);

            /*
             * Airfoil integration
             */
            final boolean top = (cc < count2);

            Float fz = volume.airfoilZ(station,x,y,span,top);
            if (null != fz){
                /*
                 * Blending function
                 */
                z = (uniform * fz)+(iuniform * zr);
            }
            else {

                z = zr;
            }
            vertices[cc+Y] = (float)z;
        }

        this.vertices = vertices;

        this.area = fv3.math.FastArea.Area2(this.vertices);
    }


    public float[] getVerticesFor(float area, float radius){

        return this.generatePath(area);
    }
    public float getPathArea(){
        return this.area;
    }
    public float[] getPathVertices(){
        return this.vertices.clone();
    }
    public boolean isPath(){
        return true;
    }
    public boolean isHyperbolic(){
        return true;
    }
    public boolean isSectional(){
        return false;
    }
    public float getHyperbolicSector(){
        return this.model.sector;
    }
    public float getHyperbolicSectorRatio(){
        return this.model.sectorR;
    }
}
